#ifndef Point_First
#define Point_First
#ifdef __GNUG__
#pragma interface
#endif

#include "Types.h"
#include "Stream.h"

//---- Point -------------------------------------------------------------------

class Point {
public:
	Point();
	Point(int xy);
	Point(int sx, int sy);
	Point(float sx, float sy);

	int &operator[](bool b);

	friend Point operator+(const Point &p1, const Point &p2);
	friend Point operator-(const Point &p);
	friend Point operator-(const Point &p1, const Point &p2);
	friend Point operator*(const Point &p1, const Point &p2);
	friend Point operator/(const Point &p1, const Point &p2);

	friend Point Scale(const Point &p, const Point &num, const Point &denom);
	friend Point Scale(const Point &p, float sx, float sy);
	
	Point operator+=(const Point &p);
	Point operator-=(const Point &p);
	Point operator*=(const Point &p);
	Point operator/=(const Point &p);

	Point Half() const;

	friend bool operator==(const Point &p1, const Point &p2);
	friend bool operator!=(const Point &p1, const Point &p2);
	friend bool operator>(const Point &p1, const Point &p2);
	friend bool operator<(const Point &p1, const Point &p2);
	friend bool operator>=(const Point &p1, const Point &p2);
	friend bool operator<=(const Point &p1, const Point &p2);

	friend Point Abs(const Point &p);
	friend Point Sign(const Point &p);
	friend Point Min(const Point &p1, const Point &p2);
	friend Point Max(const Point &p1, const Point &p2);
	friend Point Range(const Point &lo, const Point &up, const Point &p);
	friend Point Half(const Point &p);
	friend float Phi(const Point &p);
	
	friend float Length(const Point &p);
		// return sqrt(p.x*p.x + p.y*p.y);
	
	friend Point PolarToPoint(double ang, double fx, double fy);
		// return Point(fx*cos(ang), fy*sin(ang));

	friend void Swap(Point &p1, Point &p2);

	friend Point Flip(const Point &p);

	friend OStream& operator<< (OStream &s, const Point &p);
	friend IStream& operator>> (IStream &s, Point &p);
	
	const char *AsString() const;

public:
	int x, y;
};

SimpleMetaDef(Point);

extern const Point
	gPoint_1, gPoint0, gPoint1, gPoint2, gPoint3,
	gPoint4, gPoint5, gPoint6, gPoint7, gPoint8,
	gPoint10, gPoint16, gPoint32, gPoint64;

inline Point::Point()
	{ x= y= 0; }
inline Point::Point(int xy)
	{ x= y= xy; }
inline Point::Point(int sx, int sy)
	{ x= sx; y= sy; }
inline Point::Point(float sx, float sy)
	{ x= (int)sx; y= (int)sy; }
inline int &Point::operator[](bool b)
	{ if (b) return y; else return x; }
inline Point Point::operator+=(const Point &p)
	{ x+= p.x; y+= p.y; return *this; }
inline Point Point::operator-=(const Point &p)
	{ x-= p.x; y-= p.y; return *this; }
inline Point Point::operator*=(const Point &p)
	{ x*= p.x; y*= p.y; return *this; }
inline Point Point::operator/=(const Point &p)
	{ x/= p.x; y/= p.y; return *this; }
inline Point operator+(const Point &p1, const Point &p2)
	{ return Point(p1.x + p2.x, p1.y + p2.y); }
inline Point operator-(const Point &p)
	{ return Point(-p.x, -p.y); }
inline Point operator-(const Point &p1, const Point &p2)
	{ return Point(p1.x - p2.x, p1.y - p2.y); }
inline Point operator*(const Point &p1, const Point &p2)
	{ return Point(p1.x * p2.x, p1.y * p2.y); }
inline Point operator/(const Point &p1, const Point &p2)
	{ return Point(p1.x / p2.x, p1.y / p2.y); }             
inline bool operator==(const Point &p1, const Point &p2)
	{ return (bool) (p1.x == p2.x && p1.y == p2.y); }
inline bool operator!=(const Point &p1, const Point &p2)
	{ return (bool) (p1.x != p2.x || p1.y != p2.y); }
inline bool operator>(const Point &p1, const Point &p2)
	{ return (bool) (p1.x > p2.x && p1.y > p2.y); }
inline bool operator<(const Point &p1, const Point &p2)
	{ return (bool) (p1.x < p2.x && p1.y < p2.y); }
inline bool operator>=(const Point &p1, const Point &p2)
	{ return (bool) (p1.x >= p2.x && p1.y >= p2.y); }
inline bool operator<=(const Point &p1, const Point &p2)
	{ return (bool) (p1.x <= p2.x && p1.y <= p2.y); }

#endif
